/**
 * 
 */
package com.baijia.tianxiao.push.biz.channel.imp;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.baijia.tianxiao.push.biz.channel.StandardChannel;
import com.baijia.tianxiao.push.biz.channel.StandardChannelUtils;
import com.baijia.tianxiao.push.biz.channel.client.PushRet;
import com.baijia.tianxiao.push.enums.ChannelTypeEnum;
import com.baijia.tianxiao.push.enums.DeviceTypeEnum;
import com.baijia.tianxiao.push.model.PushChannelConfig;
import com.baijia.tianxiao.push.result.BasePushResult;
import com.baijia.tianxiao.push.service.PushChannelConfigService;

import nsp.NSPClient;
import nsp.OAuth2Client;
import nsp.support.common.AccessToken;
import nsp.support.common.NSPException;

/**
 * @author leiruiqi
 *
 */

@Component
public class HuaweiPushChannelImpl implements StandardChannel{
	
	private static Logger logger = LoggerFactory.getLogger(HuaweiPushChannelImpl.class); 
	
	//BaiduPushClient pushClient;
	
	private Map<String,NSPClient> pushClientMap;
	
	@Resource
	private PushChannelConfigService pushChannelConfigService;
	
	public static final String TIMESTAMP_NORMAL = "yyyy-MM-dd HH:mm:ss";
	
	@PostConstruct
	public void init(){
		// 1. get apiKey and secretKey from developer console
		//String apiKey = "i30C5KZPV4eUNgsl15mQ4Gyh";
		//String secretKey = "zqNmmO7ywrADSdD7GeBwlFU6zpysvq4k";
		//PushKeyPair pair = new PushKeyPair(apiKey, secretKey);

		// 2. build a BaidupushClient object to access released interfaces
		//pushClient = new BaiduPushClient(pair,
		//		BaiduPushConstants.CHANNEL_REST_URL);

		// 3. register a YunLogHandler to get detail interacting information
		// in this request.
		pushClientMap = new HashMap<String,NSPClient>();
		
		// 放进统一的ChannelMap中
		
		StandardChannel.channelMap.put(ChannelTypeEnum.HUAWEI.name(), this);
	}
	
	private NSPClient getClient(DeviceTypeEnum deviceType,String appId,Integer developStatus){
		String key = StandardChannelUtils.buildClientKey(deviceType, appId, developStatus);
		NSPClient client =  pushClientMap.get(key);
		if(client == null){
			PushChannelConfig channelApp = pushChannelConfigService.getByChannelTypeAndIdByCache(ChannelTypeEnum.HUAWEI.name(),deviceType, appId,developStatus);
			if(channelApp != null){
				AccessToken access_token = null;
				OAuth2Client oauth2Client = new OAuth2Client();
				InputStream stream;
	            try {
					stream = new ClassPathResource("/mykeystorebj.jks").getInputStream();
					oauth2Client.initKeyStoreStream(new ClassPathResource("/mykeystorebj.jks").getInputStream(),
							"123456");
					access_token = oauth2Client.getAccessToken("client_credentials", channelApp.getAppId(),
							channelApp.getAppSecret());
				} catch (Exception e) {
					logger.error("huawei client init error",e);
					return null;
				}
	            if(access_token == null){
	            	return null;
	            }
				client = new NSPClient(access_token.getAccess_token());
	            
	            client.initHttpConnections(30, 50);//设置每个路由的连接数和最大连接数
	            //设置http超时时间
	            client.setTimeout(10000, 15000);
	            try {
					client.initKeyStoreStream(stream, "123456");
				} catch (Exception e) {
					logger.error("huawei client initKeyStoreStream error",e);
					return null;
				}
				pushClientMap.put(appId, client);
			}
			
		}
		
		return client;
	}
	

	public BasePushResult sendPushMsg(JSONObject messageInfo, String appId,String deviceToken,String deviceType,Integer developStatus,Integer status) {
		DeviceTypeEnum typeEnum = DeviceTypeEnum.getByName(deviceType);
		if(typeEnum == null){
			return new BasePushResult(false, "deviceType not suport");	
		}
		
		NSPClient pushClient = getClient(typeEnum,appId,developStatus);
		
		
		if(pushClient == null){
			return new BasePushResult(false, "appId not config");	
		}
		//JSONObject jsono = null;
		Map<String,Object> messageBody = null;
		
		if(typeEnum == DeviceTypeEnum.ANDROID){
			messageBody = buildHuaweiAndroidMessagebody(messageInfo,deviceToken);
		}
		else if(typeEnum == DeviceTypeEnum.IOS){
			return new BasePushResult(false, "deviceType not suport");	
		}
		if(messageBody == null){
			return new BasePushResult(false, "deviceType not suport");		
		}
		try {
			
	        //接口调用
	        PushRet resp = single_send(pushClient,messageBody);
	        int resultCode = resp.getResultcode();
	        //过期6,无效12 
			if(resultCode == 6 ||resultCode == 12){
				//清除无效client，重新获取，重新发请求
				pushClientMap.remove(appId);
				NSPClient client = getClient(typeEnum,appId,developStatus);
				resp = single_send(client,messageBody);
			}
			return new BasePushResult(true, null);
		} catch (NSPException e) {
			logger.error("",e);
			return new BasePushResult(false, "");
		} catch (Exception e) {
			logger.error("",e);
			return new BasePushResult(false, "");
		}
		
		//
		
	}
	
	
	private Map<String,Object> buildHuaweiAndroidMessagebody(JSONObject messageInfo,String deviceToken){
		long currentTime = System.currentTimeMillis();
        SimpleDateFormat dataFormat = new SimpleDateFormat(TIMESTAMP_NORMAL);
		//必选
        //0：高优先级
        //1：普通优先级
        //缺省值为1
        int priority = 0;
        
        //消息是否需要缓存，必选
        //0：不缓存
        //1：缓存
        //  缺省值为0
        int cacheMode = 1;
        
        //标识消息类型（缓存机制），必选
        //由调用端赋值，取值范围（1~100）。当TMID+msgType的值一样时，仅缓存最新的一条消息
        int msgType = 1;
        
        //unix时间戳，可选
        //格式：2013-08-29 19:55
        // 消息过期删除时间
        //如果不填写，默认超时时间为当前时间后48小时
        String expire_time = dataFormat.format(currentTime + 3 * 60 * 60 * 1000);
        
		Map<String,Object> hashMap = new HashMap<String,Object>();
		hashMap.put("deviceToken", deviceToken);
		
        hashMap.put("message", messageInfo.toJSONString());
        hashMap.put("priority", priority);
        hashMap.put("cacheMode", cacheMode);
        hashMap.put("msgType", msgType);
        hashMap.put("expire_time", expire_time);
        return hashMap;
	}
	 /**
     * 单发消息
     * @param client
     * @throws NSPException
     */
    public PushRet single_send(NSPClient client,JSONObject messageInfo,String deviceToken)
        throws NSPException
    {
    	Map<String,Object> messageBody =  buildHuaweiAndroidMessagebody(messageInfo,deviceToken);
      
        //接口调用
        PushRet resp = client.call("openpush.message.single_send", messageBody, PushRet.class);
        
        //打印响应
        System.err.println("单发接口消息响应:" + resp.getResultcode() + ",message:" + resp.getMessage());
        return resp;
    }
    
    /**
     * 单发消息
     * @param client
     * @throws NSPException
     */
    public PushRet single_send(NSPClient client,Map<String,Object> messageBody)
        throws NSPException
    {
    	 
        //接口调用
        PushRet resp = client.call("openpush.message.single_send", messageBody, PushRet.class);
        
        //打印响应
        System.err.println("单发接口消息响应:" + resp.getResultcode() + ",message:" + resp.getMessage());
        
        return resp;
    }
    
	
	public JSONObject buildAndroidNotification(JSONObject pushMessage){
		JSONObject notification = new JSONObject();
		
		notification.put("description",pushMessage.get("description"));
		
		JSONObject jsonCustormCont = new JSONObject();
		jsonCustormCont.put("t", "1"); //消息类型 0:默认系统消息，1:IM消息,2:问答消息 3:找老师消息
		jsonCustormCont.put("f", "b"); //消息来源，b:百度
		jsonCustormCont.put("s",pushMessage.get("s"));   //schema跳转
		jsonCustormCont.put("cc", "xxx"); //回调码
		
		JSONObject notify = new JSONObject();
		notify.put("sound", "0");
		notify.put("shake", "0");
		notify.put("notice", "0");
		jsonCustormCont.put("notification", notify);
		
		notification.put("custom_content", jsonCustormCont);
		
		return notification;
	}

	public JSONObject buildIOSNotification(JSONObject pushMessage){
		
		JSONObject notification = new JSONObject();
		JSONObject jsonAPS = new JSONObject();
		jsonAPS.put("alert", pushMessage.get("description"));
		jsonAPS.put("sound", "default"); // 设置通知铃声样式，例如"ttt"，用户自定义。
		notification.put("aps", jsonAPS);
				
		notification.put("t", "1"); //消息类型 0:默认系统消息，1:IM消息,2:问答消息 3:找老师消息
		notification.put("f", "b"); //消息来源，b:百度
		notification.put("cc", "xxx"); //回调码
		notification.put("s",pushMessage.get("s"));   //schema跳转
		
		return notification;
	}

	@Override
	public void nofifyChannelConfigChange() {
		pushClientMap.clear();
		logger.info("huawei channel clear pushClientMap end");
	}
	
	/*public PushMsgToSingleDeviceResponse sendNotification(BaiduPushClient pushClient,JSONObject notification,String deviceToken,Integer status)throws PushClientException,
	PushServerException {
		
		PushMsgToSingleDeviceRequest request = new PushMsgToSingleDeviceRequest()
				.addChannelId(deviceToken)
				.addMsgExpires(new Integer(3600)). // 设置message的有效时间
				addMessageType(1).// 1：通知,0:透传消息.默认为0 注：IOS只有通知.
				addMessage(notification.toString());
			
			if(status == null){
				request.addDeviceType(3);
			}
			else if(status<=2){
				request.addDeployStatus(status). // IOS,
				// DeployStatus
				// => 1: Developer
				// 2: Production.
				addDeviceType(4);// deviceType => 3:android, 4:ios
			}
			
			PushMsgToSingleDeviceResponse response = null;
		try {
			response = pushClient
					.pushMsgToSingleDevice(request);
			// Http请求结果解析打印
			System.out.println("msgId: " + response.getMsgId() + ",sendTime: "
					+ response.getSendTime());
			return response;
		} catch (PushClientException e) {
			
			 * ERROROPTTYPE 用于设置异常的处理方式 -- 抛出异常和捕获异常,'true' 表示抛出, 'false' 表示捕获。
			 
			if (BaiduPushConstants.ERROROPTTYPE) {
				throw e;
			} else {
				e.printStackTrace();
			}
		} catch (PushServerException e) {
			if (BaiduPushConstants.ERROROPTTYPE) {
				throw e;
			} else {
				System.out.println(String.format(
						"requestId: %d, errorCode: %d, errorMessage: %s",
						e.getRequestId(), e.getErrorCode(), e.getErrorMsg()));
			}
		}
		finally{
			return response; 
		}
			
	}*/
	
	/*public static void main(String[] args) {
		BaiduPushChannel channel = new BaiduPushChannel();
		channel.init();
		PushBindRecord record = new PushBindRecord();
		record.setUserId("123-123");
		record.setUserType("tx");
		record.setDeviceDomain(DeviceDomainEnum.MOBILE.name());
		record.setDeviceType(DeviceTypeEnum.ANDROID.name());
		channel.sendPushMsg(messageInfo, record., deviceType, status)
	}*/
}